LWC ( Lighting Web Component ) で @wireデコレータに紐付けた Apex の呼び出し結果をリフレッシュする方法
サンプル
動作イメージ
サンプルの動作イメージです。 日付を指定して「検索」ボタンをクリックすると、該当する日付を「完了予定日」に持つ商談の情報をdatatableに再レンダリングします。
コードと解説
このサンプルは Salesforce の LWC ( Lightning Web Component ) にて、@wireデコレータに紐付けたApexの呼び出し結果をリフレッシュするサンプルになっています。
import { LightningElement, wire } from 'lwc'; import { refreshApex } from '@salesforce/apex'; import getOpportunities from '@salesforce/apex/SomeController.getOpportunities'; const TODAY = new Date(); const COLUMNS = [ { label: '取引先', fieldName: 'AccountUrl', type: 'url', typeAttributes: {label: { fieldName: 'AccountName' }, target: '_blank'}}, { label: '商談', fieldName: 'OpportunityUrl', type: 'url', typeAttributes: {label: { fieldName: 'OpportunityName' }, target: '_blank'}} ]; export default class SomeComponent extends LightningElement { wireExecCounter = 0; error; /** datatableのカラム設定 */ columns = COLUMNS; /** Apex実行結果を再レンダリングに対応させるために、結果を保持する変数 */ wiredOpportunityResult; get isLoading() { return !this.wiredOpportunityResult.data && !this.wiredOpportunityResult.error; } /* 商談検索対象の日付 */ targetDate = this.formatDate(new Date(TODAY.getFullYear(), TODAY.getMonth(), TODAY.getDay())); /* Apexコール結果の保持用 */ opportunities = []; @wire(getOpportunities, { targetDate: '$targetDate', wireExecCounter: '$wireExecCounter' }) async wiredOpportunity(result) { this.wiredOpportunityResult = result; const { data, error } = result; if ( data ) { this.opportunities = await Promise.all( data.map(async (opportunity) => { const ret = {}; ret.Id = opportunity.Id; if ( opportunity.AccountId ) { ret.AccountName = opportunity.Account.Name; ret.AccountUrl = `/${opportunity.AccountId}`; } ret.OpportunityName = opportunity.Name; ret.OpportunityUrl = `/${opportunity.Id}`; return ret; }) ); this.error = undefined; } else if ( error ) { this.opportunities = []; this.error = error; } } /* datatableのデータクリア */ clearDatatable() { this.wiredOpportunityResult.data = null; this.wiredOpportunityResult.error = null; this.opportunities = []; } /* 検索処理 */ search() { this.clearDatatable(); this.wireExecCounter++; // wire関数の実行回数をインクリメントしてキャッシュを無効化 this.targetDate = this.template.querySelector('[data-id="targetDate"]').value; refreshApex(this.wiredOpportunityResult); } /* 日付をYYYY-MM-DDの書式で返すメソッド */ formatDate(dt) { var y = dt.getFullYear(); var m = ('00' + (dt.getMonth()+1)).slice(-2); var d = ('00' + dt.getDate()).slice(-2); return (y + '-' + m + '-' + d); } }
@wireデコレータで紐付けられてコールされるApexコードは次のようにしています。
public with sharing class SomeController { @AuraEnabled(cacheable=true) public static List<Opportunity> getOpportunities(Date targetDate) { return [ SELECT Id, Name, AccountId, Account.Name FROM Opportunity WHERE CloseDate = :targetDate ]; } }
テンプレートは次のようになります。
<!-- sldsValidatorIgnore --> <template> <lightning-card title="検索"> <div> <div class="row slds-align_absolute-center"> <lightning-input type="date" label="検索日付(完了予定日)" data-id="targetDate" value={targetDate}></lightning-input> </div> <div class="row slds-align_absolute-center" style="margin: 10px;"> <lightning-button label="検索" onclick={search} class="slds-button"></lightning-button> </div> </div> </lightning-card> <lightning-card title="実行"> <div class="bootstrap"> <div if:false={isLoading}> <lightning-datatable key-field="Id" data={opportunities} columns={columns} > </lightning-datatable> </div> <div if:true={isLoading} class="slds-spinner_inline spinner-padding"> <lightning-spinner variant="brand" alternative-text="Loading..." size="medium" > </lightning-spinner> </div> </div> </lightning-card> </template>
ポイントはメンバ変数(JavaScriptコードの20行目)wiredOpportunityResult
を用意することです。この変数は@wireデコレータで紐付けたApexメソッド(SomeController.getOpportunities
)の実行結果をリフレッシュに対応させるために、Apexメソッドの実行結果を保持する変数です。
33行目の
this.wiredOpportunityResult = result;
で結果を保持させています。
このようにメンバ変数に結果を保持させておいた上で、再レンダリングによってリフレッシュしたい際にrefreshApex
メソッドにこの変数を渡すことで@wireデコレーションしたApexメソッドの再コールが行われます。サンプルでは64〜70行目のsearchメソッドにて、検索条件(targetDate)を再設定した後に
refreshApex(this.wiredOpportunityResult);
でApexメソッドの再コールが行われ、this.opportunities
への商談データの詰め込みが再度行われてdatatableがリフレッシュされます。
注意点
34行目でresult.data
とresult.error
を取り出しています。
const { data, error } = result;
このdata(result.data
)をメンバ変数にセットして、refreshApexメソッドに渡してもリフレッシュできそうに思ってしまいますが、できませんので注意してください。@wireデコレータで直接渡された引数(ここではresult
)をそのまま丸ごとメンバ変数にセットしておく必要があります。
その他のTips
このサンプルでは検索中のLoading表示をするサンプルにもなっています。
ローディング状態を判定するisLoading
を下記のように実装しています。
get isLoading() { return !this.wiredOpportunityResult.data && !this.wiredOpportunityResult.error; }
また、キャッシュを効かせずに確実にリフレッシュさせるために、wireExecCounter
というメンバ変数を用意して、Apexメソッドのコールをするたびにカウントアップして、Apexメソッドに対して異なる引数を呼び出すようにしています。